package MultiThread.AlternatePrinting;

import java.util.concurrent.locks.*;

/**
 * @author Jimmy Zhan WORKSTATION
 * @since 2023/8/5 16:35
 * 说明： ReentrantLock 可重入锁，等待和唤醒使用的是 await 和 signal
 */

public class ReentrantLockAlterPrint {
    public static void main(String[] args) {
        AwaitSignal awaitSignal = new AwaitSignal(50);
        Condition a = awaitSignal.newCondition();
        Condition l = awaitSignal.newCondition();
        Condition i = awaitSignal.newCondition();

        new Thread(() -> {
            awaitSignal.printAli("a", a, l);
        }).start();
        new Thread(() -> {
            awaitSignal.printAli("l", l, i);
        }).start();
        new Thread(() -> {
            awaitSignal.printAli("i", i, a);
        }).start();
        // 一上来大家都是在condition中await的，所以需要主线程来启动一下
        // 先上锁，上完锁后唤醒a休息室中的线程，最后在finally中解锁
        awaitSignal.lock();
        try {
            System.out.println("主线程发起开始命令");
            a.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            awaitSignal.unlock();
        }
    }
}

class AwaitSignal extends ReentrantLock {
    private int loopNum;        // 控制循环次数
    public AwaitSignal(int loopNum){
        this.loopNum = loopNum;
    }
    // 参数：1.需要打印的内容  2. 当前进入的休息室  3. 接下来要进入的休息室
    public void  printAli (String str, Condition current, Condition next) {
        for (int i = 0; i < loopNum; ++i) {
            lock();     // lock() 和 unlock() 是继承的可重入锁中的方法。要成对存在，unlock放在finally中
            try {
                // 当前的线程先是在await，一旦被唤醒了，就往下执行：打印 -> 唤醒next休息室中的线程
                // 一上来大家都是在condition中await的
                current.await();
                System.out.print(str);
                next.signal();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                unlock();
            }
        }
    }

}